﻿using System.Collections.Generic;
using UnityEngine;
using UnityView.Utils;

namespace UnityView
{
    // 多种元素列表适配器
    public interface IMultipleAdapter
    {
        int GetCount();
        IViewLayout GetConvertView(int index, IViewLayout view);
        float GetItemSize(int index);
        int GetItemType(int index);
    }

    /// <summary>
    /// 支持多种 Item 的 ListView
    /// </summary>
    public class MultipleListView : AbsAdapterView<IMultipleAdapter>
    {
        protected readonly AdapterCellCache<AdapterCellHolder>[] Caches;
        protected readonly LinkedList<AdapterCellHolder> Items = new LinkedList<AdapterCellHolder>();
        protected int[] TypeCache;

        // 高度缓存数组
        protected float[] SizeCache;
        // 起点缓存数组
        protected float[] AnchorCache;

        public MultipleListView(int typeCount)
        {
            Caches = new AdapterCellCache<AdapterCellHolder>[typeCount];
            for (int i = 0; i < typeCount; i++)
            {
                Caches[i] = new AdapterCellCache<AdapterCellHolder>();
            }
            // 初始化数组缓存数组
            SizeCache = new float[ItemCount];
            AnchorCache = new float[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                SizeCache[i] = -1;
                AnchorCache[i] = -1;
            }
        }

        public override void OnAdapterAttached(IMultipleAdapter adapter)
        {
            ItemCount = Adapter.GetCount();
            TypeCache = new int[ItemCount];
            if (SizeCache.Length < ItemCount)
            {
                float[] heightArray = new float[ItemCount];
                float[] anchorArray = new float[ItemCount];
                SizeCache.CopyTo(heightArray, 0);
                AnchorCache.CopyTo(anchorArray, 0);
                SizeCache = heightArray;
                AnchorCache = anchorArray;
            }
            float anchor = 0;
            for (int i = 0; i < ItemCount; i++)
            {
                float height = Adapter.GetItemSize(i);
                SizeCache[i] = height;
                AnchorCache[i] = anchor;
                anchor += height;
                TypeCache[i] = Adapter.GetItemType(i);
            }
            UpdateVisibleItemCount();
            Reload();
            RepositionFooter();
        }

        public override void UpdateVisibleItemCount()
        {
            if (ItemCount == 0)
            {
                VisibleItemCount = 0;
                return;
            }
            VisibleItemCount = 0;
            int index = GetStartIndex();
            float height = -SizeCache[index];
            while (index < ItemCount && height < Height)
            {
                height += SizeCache[index];
                index++;
                VisibleItemCount++;
            }
        }

        public override Vector2 GetItemPosition(int index)
        {
            return Orientation == Orientation.Horizontal
                ? new Vector2(AnchorCache[index] - HeaderViewSize, 0)
                : new Vector2(0, -AnchorCache[index] - HeaderViewSize);
        }

        public override int GetItemIndex(Vector2 vector2)
        {
            return 0;
        }

        protected override int GetStartIndex()
        {
            return GetStartIndex(ContentTransform.anchoredPosition.y - HeaderViewSize);
        }

        protected int GetStartIndex(float position)
        {
            StartIndex = Algorithm.BinarySearchFloat(AnchorCache, 0, ItemCount, position);
            if (StartIndex < 0) StartIndex = 0;
            return StartIndex;
        }

        // 记录上次更新的位置
        protected Vector2 LastRepositionPosition = Vector2.zero;
        public override void Reload()
        {
            // 停止滚动
            ScrollRect.StopMovement();
            if (Adapter == null) return;
            ItemCount = Adapter.GetCount();
            UpdateContentSize();
            StartIndex = GetStartIndex();

            //int visibleCount = Math.Min(VisibleItemCount, ItemCount);
            UpdateVisibleItemCount();

            List<AdapterCellHolder> cells = new List<AdapterCellHolder>();
            for (int i = 0; i < VisibleItemCount; i++)
            {
                LinkedListNode<AdapterCellHolder> node = Items.First;
                cells.Add(node == null ? new AdapterCellHolder() : node.Value);
                Items.RemoveFirst();
            }
            foreach (var item in Items)
            {
                Caches[TypeCache[item.Index]].Enqueue(item);
            }
            Items.Clear();

            for (int i = 0; i < VisibleItemCount; i++)
            {
                var cell = cells[i];
                int index = StartIndex + i;
                IViewLayout viewLayout = Adapter.GetConvertView(index, cell.View);
                viewLayout.ParentView = ContentView;
                var size = Orientation == Orientation.Horizontal ? new Vector2(SizeCache[index], Height) : new Vector2(Width, SizeCache[index]);
                cell.Update(viewLayout, index, GetItemPosition(index), size);
                Items.AddLast(cell);
            }
        }

        public override void LayoutSubviews()
        {
            UpdateVisibleItemCount();
            float delta = Orientation == Orientation.Horizontal
                ? LastRepositionPosition.x - ContentTransform.anchoredPosition.x
                : ContentTransform.anchoredPosition.y - LastRepositionPosition.y;
            // 通过偏移位置的正负确定视图的行进方向，这决定了双向链表的遍历顺序
            if (delta > 0)
            {
                // 此时视图向上运动，StartIndex 增大 
                LinkedListNode<AdapterCellHolder> node = Items.First;
                int count = 0;
                while (node != null)
                {
                    if (node.Value.Index >= StartIndex) break;
                    count++;
                    node = node.Next;
                }
                for (int i = 0; i < count; i++)
                {
                    AdapterCellHolder item = Items.First.Value;
                    Caches[TypeCache[item.Index]].Enqueue(item);
                    Items.RemoveFirst();
                }
                count = Items.Count;
                int missing = VisibleItemCount - count;
                for (int i = 0; i < missing; i++)
                {
                    //int index = StartIndex + i - 1;
                    int index = Items.Count == 0 ? 0 : Items.Last.Value.Index + 1;

                    AdapterCellHolder cellHolder = Caches[TypeCache[index]].Dequeue();
                    IViewLayout viewLayout = Adapter.GetConvertView(index, cellHolder.View);
                    viewLayout.ParentView = ContentView;
                    var size = Orientation == Orientation.Horizontal ? new Vector2(SizeCache[index], Height) : new Vector2(Width, SizeCache[index]);
                    cellHolder.Update(viewLayout, index, GetItemPosition(index), size);
                    Items.AddLast(cellHolder);
                }
            }
            else
            {
                // 此时视图向下运动
                LinkedListNode<AdapterCellHolder> node = Items.Last;
                int count = 0;
                while (node != null)
                {
                    if (node.Value.Index < StartIndex + VisibleItemCount) break;
                    count++;
                    node = node.Previous;
                }
                for (int i = 0; i < count; i++)
                {
                    AdapterCellHolder item = Items.Last.Value;
                    Caches[TypeCache[item.Index]].Enqueue(item);
                    Items.RemoveLast();
                }
                count = Items.Count;
                int missing = VisibleItemCount - count;
                for (int i = 0; i < missing; i++)
                {
                    int index = Items.Count == 0 ? 0 : Items.First.Value.Index - 1;
                    if (index < 0) index = 0;

                    AdapterCellHolder cellHolder = Caches[TypeCache[index]].Dequeue();
                    IViewLayout viewLayout = Adapter.GetConvertView(index, cellHolder.View);
                    viewLayout.ParentView = ContentView;
                    var size = Orientation == Orientation.Horizontal ? new Vector2(SizeCache[index], Height) : new Vector2(Width, SizeCache[index]);
                    cellHolder.Update(viewLayout, index, GetItemPosition(index), size);
                    Items.AddFirst(cellHolder);
                }
            }

            LastRepositionPosition = ContentTransform.anchoredPosition;
        }

        public void RepositionFooter()
        {
            
        }

        protected override Vector2 UpdateContentSize()
        {
            if (ItemCount == 0) return Vector2.zero;
            ContentTransform.sizeDelta = Orientation == Orientation.Horizontal
                ? new Vector2(HeaderViewSize + FooterViewSize + AnchorCache[ItemCount - 1] + SizeCache[ItemCount - 1], Height)
                : new Vector2(Width, HeaderViewSize + FooterViewSize + AnchorCache[ItemCount - 1] + SizeCache[ItemCount - 1]);
            return ContentTransform.sizeDelta;
        }
    }
}
